// 数组创建
let arr = [1, 2, 3]
const array1 = new Array(3, 4, 5, 6, 7)

array1[0] = 10;

// array array array array array Array Array Array Array Array

arr.push(45);
arr.unshift(20);

// 什么是类似数组结构
let arrObj = {
    0: 1,
    length: 1
}

// index index index index index index index index index index index index

for (let index = 0; index < arr.length; index++) {
    console.log(arr[index]);
}

// item item item item item item item item item item item item item item

for (let item of arr) {
    console.log(item);
}

arr.forEach((item, index, self) => {
    // item 元素
    // index 索引值
    // self 数组自身
});

let str = '123456789';
str.concat('4', '5', '6'); // '123456'

// const arr = [1, 2, 3]
/**
 * 链接：连接参数并【返回新数组】
 * 参数中的元素或数组（如果参数为数组时，会将数组平铺到原始数组中)
 * ！并不会修改原始数组
 */
arr.concat(4, [5, 6, 7], 8); // [1, 2, 3, 4, 5, 6, 7, 8]

/**
 * 合并：将数组中的所有元素合并成一个字符串并返回
 * 如果调用join()什么参数都没传，则会返回一个由逗号分隔的元素字符串
 * ！并不会修改原始数组
 */
arr.join();

/**
 * 末尾追加：向后追加一个元素
 * 会直接修改原始数组
 */
arr.push(1);

/**
 * 末尾删除：从最后面删除一个元素，并将其返回
 * 会直接修改原始数组
 */
const lastItem = arr.pop();

/**
 * 头部追加：在最前面追加一个元素
 * 会直接修改原始数组
 */
arr.unshift();

/**
 * 头部删除：从最前面删除一个元素，并将其返回
 * 会直接修改原始数组
 */
const firstItem = arr.shift();

str.slice(1, 3); // 字符串切片
str.substring(1, 3); // 字符串截取（与切片类似）
/**
 * '0123456789'
 * str.slice(0, 3） // '012'
 *
 * arr2 = [0,1,2,3,4,5,6,7,8,9]
 * arr2.slice(0,3) // [0, 1, 2]
 */
/**
 * 数组切片：从原始数组中 第一个参数索引 到（第二个参数索引-1）的返回提取出一个新的数组切片并返回
 * 不会影响原始数组
 */
arr.slice(1, 3);

/**
 * splice
 * 通过指定索引，和想要删除的元素个数，从原始数组中删除指定元素
 * 会直接修改原始数组的值
 * 第一个参数 start：删除的起始位置索引
 * 第二个参数 deleteCount：要删除的个数
 * 第三个及其后面的参数：会插入到原始数组中
 * 特点：
 * 1. 会将删除的元素组成新的数组并返回
 * 2. 会直接将原始数组中的元素删掉
 * 3. 直接删除数组中指定位置的元素（仅删除）；或删除指定位置的元素，同时插入新的值(删除并替换)。
 */
arr.splice(1, 3, 20, 30, 40);

// 字符位于（索引）
str.charAt(5);
str[5]; // 字符串只能通过下标读取字符，但不能修改

// 位于（索引）
arr.at(5);
arr[5]; // 数组可以通过下标读取对应索引的元素
arr[5] = 10; // 数组可以通过下标直接修改值

/**
 * 颠倒数组元素，第一个变倒数第一个，第二个变倒数第二个，以此类推
 * 会直接影响原始数组
 */
arr.reverse();

/**
 * 数组的维度
 * 一维数组：[1, 2, 3, 4] 线性数组
 * 二维数组：[
 *     [1, 2, 3, 4], // 二位数组的每一个元素都是一个一维数组
 *     [5, 6, 7, 8],
 *     [9, 10, 11, 12],
 * ] // 平面数组
 * 三维数组：[
 *     [
 *         [1, 2, 3, 4],
 *         [5, 6, 7, 8],
 *         [9, 10, 11, 12],
 *     ],
 *     [
 *         [1, 2, 3, 4],
 *         [5, 6, 7, 8],
 *         [9, 10, 11, 12],
 *     ],
 *     [
 *         [1, 2, 3, 4],
 *         [5, 6, 7, 8],
 *         [9, 10, 11, 12],
 *     ],
 * ]
 */

/**
 * 拍扁:
 * 1. 降维：降1维。3维降到2维，2维降到1维
 * 2. 只能降第一层数组的元素
 */
arr.flat();

const w2 = [
    [1, 2, 3, 4], // 二位数组的每一个元素都是一个一维数组
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]

const w3 = [
    [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
    ],
    [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
    ],
    [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
    ],
];
const wx_after_flat = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],

    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],

    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]

/**
 * 内部排序
 * 1. 会直接影响原始数组
 * 2. 如果元素是字母、数字、特殊字符，会根据元素在 UTF-16 中的编码顺序进行排序
 * 3. 传入比较函数（见下方）
 */
arr.sort();
/**
 * sort(比较函数)
 */
arr.sort((a, b) => {
    let x = a - b;
    // x < 0 | x >= 0
    // 如果 x < 0, 则 a b 的位置交换
    // 如果 x >= 0，则 a b 的位置保持不变
    return x;
});

// str = '123456789';
/**
 * 从前往后，查找第一个符合条件的元素的索引位置
 * indexOf(目标元素， 起始位置)
 */
str.indexOf('7', 2); // 6
arr = ['1', '2', '3', '4', '5', '6', '777', '8', '9']
arr.indexOf('777', 2); // 6

/**
 * 从后往前，查找第一个符合条件的元素的索引位置
 * lastIndexOf(目标元素，起始位置)
 */
str.lastIndexOf('7', 8); // 6
arr.lastIndexOf('777', 8); // 6

/**
 * 遍历数组
 * 1. 不会影响原始数组
 * 2. 唯一参数：传入一个函数，并且函数没有返回值
 */
arr.forEach(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        // 没有返回值
    }
);

/**
 * 过滤
 * 1. 不会影响原始数组
 * 2. 将不符合条件的元素排除掉，并将符合条件的元素组合成新数组并返回
 * 3. 唯一参数：传入一个函数
 */
arr.filter(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * filter 要求返回 boolean
         * 如果返回了 true，则该元素保留
         * 如果返回了 false，则该元素剔除
         */
        return item > 5; // boolean
    }
);

/**
 * 点对点修改
 * 1. 不会影响原始数组
 * 2. 遍历每一个元素的同时，将返回值替换到原索引位置，并将新的元素组成新的数组并返回
 * 3. 唯一参数：传入一个函数
 */
arr.map(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * map 要求返回一个新的（任意）元素
         */
        return item + 10;
    }
);

/**
 * 点对面并拍扁修改
 */
arr.flatMap(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * flatMap 要求返回一个新的（任意）元素或数组
         */
        return [item, '+ 10 =', item + 10];
    }
);

/**
 * 正序查找元素
 * 1. 不会影响原始函数
 * 2. 唯一参数：传入一个函数
 * 3. 如果从前往后，查找的过程中函数返回了true，则停止查找，并返回该元素
 *      也就是说，会返回数组中正序第一个符合条件的元素
 */
arr.find(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * find 要求返回 boolean
         */
        return item > 5;
    }
);

/**
 * 倒序查找元素
 * 1. 不会影响原始函数
 * 2. 唯一参数：传入一个函数
 * 3. 如果从后往前，查找的过程中函数返回了true，则停止查找，并返回该元素
 *      也就是说，会返回数组中倒序第一个符合条件的元素
 */
arr.findLast(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * findLast 要求返回 boolean
         */
        return item < 8;
    }
);

/**
 * 正序查找元素的索引值
 * 1. 不会影响原始函数
 * 2. 唯一参数：传入一个函数
 * 3. 如果从前往后，查找的过程中函数返回了true，则停止查找，并返回该元素对应的索引值
 *      也就是说，会返回数组中正序第一个符合条件的元素的索引值
 */
arr.findIndex(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * findIndex 要求返回 boolean
         */
        return item > 5;
    }
);

/**
 * 倒序查找元素的索引值
 * 1. 不会影响原始函数
 * 2. 唯一参数：传入一个函数
 * 3. 如果从后往前，查找的过程中函数返回了true，则停止查找，并返回该元素的索引值
 *      也就是说，会返回数组中倒序第一个符合条件的元素的索引值
 */
arr.findLastIndex(
    // 函数
    (item, index, self) => {
        // item 是数组中的元素
        // index 数组的索引
        // self 是数组本身

        /**
         * findLastIndex 要求返回 boolean
         */
        return item < 8;
    }
);

/**
 * 正序合并元素
 * reduce(函数, 初始值)
 * 函数(上一次的返回值, item, index, self) {
 *     return 上一次的返回值 + item
 * }
 */
arr.reduce();

/**
 * 倒序合并元素
 * reduce(函数, 初始值)
 * 函数(上一次的返回值, item, index, self) {
 *     return 上一次的返回值 + item
 * }
 */
arr.reduceRight();

// ts 属性、函数必须先声明
// js 属性、函数可以不用声明
class MyArray {
    constructor(...items) {
        // 将 items参数 存到 类的 属性items 中
        this.items = items; // 哎特母
    }

    /**
     *
     * @param fn (returnedValue, item, index, arraySelf) => { return returnedValue + item }
     * @param initValue 0
     * @returns {*}
     */
    reduce(fn, initValue) {
        let returnedValue = initValue;
        for (let index = 0; index < this.items.length; index++) {
            const item = this.items[index];
            returnedValue = fn(returnedValue, item, index, this.items)
        }

        return returnedValue;
    }

    reduceRight(fn, initValue) {
        let returnedValue = initValue;
        for (let index = this.items.length - 1; index >= 0; index--) {
            const item = this.items[index];
            returnedValue = fn(returnedValue, item, index, this.items)
        }
        return returnedValue;
    }
}

// 2天作业
// 作业1 数组全部API，会读，会写，会用
// 作业2 for 循环再加深印象

//初始化索引 let index = 0;
//循环结束条件 index < arr4.length
//循环递增语句 index++
//arr4[index]根据索引从数组中取值
// 正序
for (let index = 0; index < arr4.length; index++) {
    console.log(arr4[index]);
}
// 倒序
for (let index = arr4.length - 1; index >= 0; index++) {
    console.log(arr4[index]);
}



